#!/bin/bash

# 等保合规检测脚本 v1.2
# 功能：执行Linux服务器等保合规性自动检测
# 作者：didiplus

# 初始化设置
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
NC='\033[0m' # No Color
REPORT_FILE="/tmp/sec_check_$(date +%Y%m%d%H%M%S).log"
PASS_MAX_DAYS=90    # 密码最长有效期
PASS_MIN_DAYS=7     # 密码修改间隔
PASS_WARN_AGE=7     # 密码到期提醒
LOG_MAX_DAYS=180    # 日志保留天数

# 初始化计数器
total_checks=0
passed=0
failed=0
warnings=0

# 检测结果记录函数
log_result() {
  local status=$1
  local message=$2
  case $status in
    "PASS") 
      echo -e "[${GREEN}PASS${NC}] $message" | tee -a $REPORT_FILE
      ((passed++))
      ((total_checks++))
      ;;
    "FAIL") 
      echo -e "[${RED}FAIL${NC}] $message" | tee -a $REPORT_FILE
      ((failed++))
      ((total_checks++))
      ;;
    "WARN") 
      echo -e "[${YELLOW}WARN${NC}] $message" | tee -a $REPORT_FILE
      ((warnings++))
      ((total_checks++))
      ;;
  esac
}

# 权限检查
if [ "$(id -u)" -ne 0 ]; then
  echo -e "${RED}错误：本脚本需要root权限执行${NC}"
  exit 1
fi

# 账号策略检测模块
check_account_policies() {
  echo -e "\n=== 账号策略检测 ==="
  
  # 密码复杂度检测
  if grep -q "minlen = 8" /etc/security/pwquality.conf && \
     grep -q "dcredit = -1" /etc/security/pwquality.conf && \
     grep -q "ucredit = -1" /etc/security/pwquality.conf && \
     grep -q "ocredit = -1" /etc/security/pwquality.conf && \
     grep -q "lcredit = -1" /etc/security/pwquality.conf; then
    log_result "PASS" "密码复杂度策略符合要求"
  else
    log_result "FAIL" "密码复杂度策略不符合要求（需包含大小写字母、数字、特殊字符，最小长度8位）"
  fi

  # 密码有效期检测
  if [ $(grep "^PASS_MAX_DAYS" /etc/login.defs | awk '{print $2}') -le $PASS_MAX_DAYS ]; then
    log_result "PASS" "密码最长有效期设置符合要求（≤${PASS_MAX_DAYS}天）"
  else
    log_result "FAIL" "密码最长有效期设置过长（当前设置：$(grep ^PASS_MAX_DAYS /etc/login.defs | awk '{print $2}')天）"
  fi

  # 登录失败处理
  if grep -q "auth required pam_tally2.so deny=5 unlock_time=900" /etc/pam.d/sshd; then
    log_result "PASS" "登录失败锁定策略已配置"
  else
    log_result "FAIL" "未配置登录失败锁定策略（应达到5次失败锁定账户，锁定时间≥15分钟）"
  fi
}

# SSH安全配置检测模块
check_ssh_config() {
  echo -e "\n=== SSH安全配置检测 ==="
  
  sshd_file="/etc/ssh/sshd_config"
  
  # 协议版本检测
  if grep -q "^Protocol 2" $sshd_file; then
    log_result "PASS" "SSH协议版本配置正确（仅使用SSHv2）"
  else
    log_result "FAIL" "SSH协议版本未限制为v2"
  fi

  # Root登录检测
  if grep -q "^PermitRootLogin no" $sshd_file; then
    log_result "PASS" "SSH禁止root直接登录"
  else
    log_result "FAIL" "SSH允许root直接登录"
  fi

  # 空闲超时检测
  if grep -q "^ClientAliveInterval 900" $sshd_file && \
     grep -q "^ClientAliveCountMax 0" $sshd_file; then
    log_result "PASS" "SSH空闲会话超时设置正确（≤900秒）"
  else
    log_result "WARN" "SSH空闲会话超时未配置或设置过长"
  fi
}

# 防火墙检测模块
check_firewall() {
  echo -e "\n=== 防火墙配置检测 ==="
  
  # 检查防火墙状态
  if systemctl is-active firewalld >/dev/null || systemctl is-active iptables >/dev/null || systemctl is-active ufw >/dev/null; then
    log_result "PASS" "防火墙服务正在运行"
    
    # 检查默认策略
    if [ $(iptables -L | grep "Chain INPUT (policy DROP)" | wc -l) -ge 1 ] || \
       [ $(firewall-cmd --list-all | grep "default zone: drop") ]; then
      log_result "PASS" "防火墙默认策略为拒绝"
    else
      log_result "WARN" "防火墙未设置默认拒绝策略"
    fi
    
    # 检查必要端口开放
    if [ $(iptables -L -n | grep ":22 " | wc -l) -ge 1 ] || \
       [ $(firewall-cmd --list-ports | grep 22/tcp) ]; then
      log_result "PASS" "SSH端口访问控制已配置"
    else
      log_result "WARN" "未明确配置SSH端口访问策略"
    fi
  else
    log_result "FAIL" "未检测到运行的防火墙服务"
  fi
}

# 服务状态检测模块
check_services() {
  echo -e "\n=== 系统服务检测 ==="
  
  # 禁用不必要的服务
  bad_services=("telnet" "rsh" "rlogin" "rexec" "vsftpd" "tftp" "ypserv")
  for service in "${bad_services[@]}"; do
    if systemctl is-enabled $service 2>/dev/null | grep -q "enabled"; then
      log_result "FAIL" "高风险服务 $service 已启用"
    else
      log_result "PASS" "服务 $service 已禁用"
    fi
  done

  # 关键服务状态检测
  good_services=("rsyslog" "auditd")
  for service in "${good_services[@]}"; do
    if systemctl is-active $service >/dev/null; then
      log_result "PASS" "关键服务 $service 运行正常"
    else
      log_result "FAIL" "关键服务 $service 未运行"
    fi
  done
}

# 日志审计检测模块
check_log_audit() {
  echo -e "\n=== 日志审计检测 ==="
  
  # 日志保留策略
  if grep -q "^rotate $LOG_MAX_DAYS" /etc/logrotate.conf; then
    log_result "PASS" "日志保留策略符合要求（≥${LOG_MAX_DAYS}天）"
  else
    log_result "FAIL" "日志保留时间不足（当前配置：$(grep ^rotate /etc/logrotate.conf)）"
  fi

  # Auditd审计规则检测
  if [ -f /etc/audit/rules.d/audit.rules ]; then
    important_rules=(
      "-w /etc/passwd -p wa -k identity"
      "-w /etc/shadow -p wa -k identity"
      "-w /etc/sudoers -p wa -k privilege"
    )
    
    for rule in "${important_rules[@]}"; do
      if ! auditctl -l | grep -q "$rule"; then
        log_result "FAIL" "缺少关键审计规则：$rule"
        return
      fi
    done
    log_result "PASS" "关键文件审计规则已配置"
  else
    log_result "FAIL" "未找到auditd配置文件"
  fi
}

# 执行所有检测
main() {
  clear
  echo "=== 开始等保合规检测 ==="
  echo "检测时间：$(date '+%Y-%m-%d %H:%M:%S')"
  echo "检测主机：$(hostname)"
  echo "生成报告：$REPORT_FILE"
  
  check_account_policies
  check_ssh_config
  check_firewall
  check_services
  check_log_audit
  
  # 汇总报告
  echo -e "\n=== 检测结果汇总 ==="
  echo "总检测项：$total_checks"
  echo -e "${GREEN}通过项：$passed${NC}"
  echo -e "${YELLOW}警告项：$warnings${NC}"
  echo -e "${RED}失败项：$failed${NC}"
  
  # 输出重要建议
  if [ $failed -gt 0 ]; then
    echo -e "\n${RED}[重要提示] 存在必须修复的失败项，请根据检测结果及时整改！${NC}"
  fi
}

# 执行主函数
main